﻿using Cordyceps.Micro.AspNetCoreMvc;
using System.ComponentModel.DataAnnotations;

namespace Cordyceps.Micro.AuthServer.HttpApi.Controllers;

public class AuthorizationController : CordycepsControllerBase
{
    //private readonly IOpenIddictApplicationManager _applicationManager;
    //private readonly IOpenIddictAuthorizationManager _authorizationManager;

    //private readonly AuthServer _authServer;

    //private readonly IOpenIddictScopeManager _scopeManager;
    ////private readonly SignInManager<ApplicationUser> _signInManager;
    ////private readonly UserManager<ApplicationUser> _userManager;

    //public AuthorizationController(
    //    IOpenIddictApplicationManager applicationManager,
    //    IOpenIddictAuthorizationManager authorizationManager,
    //    IOpenIddictScopeManager scopeManager,
    //    AuthServer authServer
    ////,SignInManager<ApplicationUser> signInManager,
    ////UserManager<ApplicationUser> userManager
    //)
    //{
    //    _applicationManager = applicationManager;
    //    _authorizationManager = authorizationManager;
    //    _scopeManager = scopeManager;
    //    _authServer = authServer;
    //    //_signInManager = signInManager;
    //    //_userManager = userManager;
    //}

    //[HttpGet("~/connect/authorize")]
    //[HttpPost("~/connect/authorize")]
    //[IgnoreAntiforgeryToken]
    //public async Task<IActionResult> Authorize()
    //{
    //    var request = HttpContext.GetOpenIddictServerRequest() ??
    //        throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");

    //    // Try to retrieve the user principal stored in the authentication cookie and redirect
    //    // the user agent to the login page (or to an external provider) in the following cases:
    //    //
    //    //  - If the user principal can't be extracted or the cookie is too old.
    //    //  - If prompt=login was specified by the client application.
    //    //  - If max_age=0 was specified by the client application (max_age=0 is equivalent to prompt=login).
    //    //  - If a max_age parameter was provided and the authentication cookie is not considered "fresh" enough.
    //    //
    //    // For scenarios where the default authentication handler configured in the ASP.NET Core
    //    // authentication options shouldn't be used, a specific scheme can be specified here.
    //    var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);

    //    var isAuthenticated = _authServer.IsAuthenticated(result, request);


    //    if (isAuthenticated)
    //    { 

    //    }


    //    if (result is not { Succeeded: true } ||
    //        ((request.HasPromptValue(PromptValues.Login) || request.MaxAge is 0 ||
    //         (request.MaxAge is not null && result.Properties?.IssuedUtc is not null &&
    //          TimeProvider.System.GetUtcNow() - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value))) &&
    //        TempData["IgnoreAuthenticationChallenge"] is null or false))
    //    {
    //        // If the client application requested promptless authentication,
    //        // return an error indicating that the user is not logged in.
    //        if (request.HasPromptValue(PromptValues.None))
    //        {
    //            return Forbid(
    //                authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
    //                properties: new AuthenticationProperties(new Dictionary<string, string?>
    //                {
    //                    [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired,
    //                    [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is not logged in."
    //                }));
    //        }

    //        // To avoid endless login endpoint -> authorization endpoint redirects, a special temp data entry is
    //        // used to skip the challenge if the user agent has already been redirected to the login endpoint.
    //        //
    //        // Note: this flag doesn't guarantee that the user has accepted to re-authenticate. If such a guarantee
    //        // is needed, the existing authentication cookie MUST be deleted AND revoked (e.g using ASP.NET Core
    //        // Identity's security stamp feature with an extremely short revalidation time span) before triggering
    //        // a challenge to redirect the user agent to the login endpoint.
    //        TempData["IgnoreAuthenticationChallenge"] = true;

    //        // For scenarios where the default challenge handler configured in the ASP.NET Core
    //        // authentication options shouldn't be used, a specific scheme can be specified here.
    //        return Challenge(new AuthenticationProperties
    //        {
    //            RedirectUri = Request.PathBase + Request.Path + QueryString.Create(
    //                Request.HasFormContentType ? Request.Form : Request.Query)
    //        });
    //    }

    //    // Retrieve the profile of the logged in user.
    //    var user = await _userManager.GetUserAsync(result.Principal) ??
    //        throw new InvalidOperationException("The user details cannot be retrieved.");

    //    // Retrieve the application details from the database.
    //    var application = await _applicationManager.FindByClientIdAsync(request.ClientId!) ??
    //        throw new InvalidOperationException("Details concerning the calling client application cannot be found.");

    //    // Retrieve the permanent authorizations associated with the user and the calling client application.
    //    var authorizations = await _authorizationManager.FindAsync(
    //        subject: await _userManager.GetUserIdAsync(user),
    //        client: await _applicationManager.GetIdAsync(application),
    //        status: Statuses.Valid,
    //        type: AuthorizationTypes.Permanent,
    //        scopes: request.GetScopes()).ToListAsync();

    //    switch (await _applicationManager.GetConsentTypeAsync(application))
    //    {
    //        // If the consent is external (e.g when authorizations are granted by a sysadmin),
    //        // immediately return an error if no authorization can be found in the database.
    //        case ConsentTypes.External when authorizations.Count is 0:
    //            return Forbid(
    //                authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
    //                properties: new AuthenticationProperties(new Dictionary<string, string?>
    //                {
    //                    [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
    //                    [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
    //                        "The logged in user is not allowed to access this client application."
    //                }));

    //        // If the consent is implicit or if an authorization was found,
    //        // return an authorization response without displaying the consent form.
    //        case ConsentTypes.Implicit:
    //        case ConsentTypes.External when authorizations.Count is not 0:
    //        case ConsentTypes.Explicit when authorizations.Count is not 0 && !request.HasPromptValue(PromptValues.Consent):
    //            // Create the claims-based identity that will be used by OpenIddict to generate tokens.
    //            var identity = new ClaimsIdentity(
    //                authenticationType: TokenValidationParameters.DefaultAuthenticationType,
    //                nameType: Claims.Name,
    //                roleType: Claims.Role);

    //            // Add the claims that will be persisted in the tokens.
    //            identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user))
    //                    .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user))
    //                    .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user))
    //                    .SetClaim(Claims.PreferredUsername, await _userManager.GetUserNameAsync(user))
    //                    .SetClaims(Claims.Role, [.. (await _userManager.GetRolesAsync(user))]);

    //            // Note: in this sample, the granted scopes match the requested scope
    //            // but you may want to allow the user to uncheck specific scopes.
    //            // For that, simply restrict the list of scopes before calling SetScopes.
    //            identity.SetScopes(request.GetScopes());
    //            identity.SetResources(await _scopeManager.ListResourcesAsync(identity.GetScopes()).ToListAsync());

    //            // Automatically create a permanent authorization to avoid requiring explicit consent
    //            // for future authorization or token requests containing the same scopes.
    //            var authorization = authorizations.LastOrDefault();
    //            authorization ??= await _authorizationManager.CreateAsync(
    //                identity: identity,
    //                subject: await _userManager.GetUserIdAsync(user),
    //                client: (await _applicationManager.GetIdAsync(application))!,
    //                type: AuthorizationTypes.Permanent,
    //                scopes: identity.GetScopes());

    //            identity.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization));
    //            identity.SetDestinations(GetDestinations);

    //            return SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);

    //        // At this point, no authorization was found in the database and an error must be returned
    //        // if the client application specified prompt=none in the authorization request.
    //        case ConsentTypes.Explicit when request.HasPromptValue(PromptValues.None):
    //        case ConsentTypes.Systematic when request.HasPromptValue(PromptValues.None):
    //            return Forbid(
    //                authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
    //                properties: new AuthenticationProperties(new Dictionary<string, string?>
    //                {
    //                    [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
    //                    [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
    //                        "Interactive user consent is required."
    //                }));

    //        // In every other case, render the consent form.
    //        default:
    //            return View(new AuthorizeViewModel
    //            {
    //                ApplicationName = (await _applicationManager.GetLocalizedDisplayNameAsync(application))!,
    //                Scope = request.Scope
    //            });
    //    }
    //}
}

public class AuthorizeViewModel
{
    [Display(Name = "Application")] public string? ApplicationName { get; set; }

    [Display(Name = "Scope")] public string? Scope { get; set; }
}